<?php
/**
 * Created by PhpStorm.
 * User: cc
 * Date: 2023/6/14
 * Time: 3:39 PM
 */

namespace App\Models\CacheModel;

use App\Models\CacheModel\lucky\AppLuckyTaskRecord;
use app\common\lib\Util;
use App\Models\Api\BaseCache;
use App\Models\Api\Fortune;
use think\Env;
use think\exception\PDOException;
use think\Log;
use AstroTool\Cache\CacheManage;

class UserAppleNotifyRecord extends BaseCache
{
    protected $table = 'wechat_backup_07_18_14_43_00.user_apple_notify_record';

    /**
     * 回调处理
     * @param $data
     * @return bool|void
     * @throws PDOException
     * @throws \Exception
     */
    public function notifyInfo($data)
    {
        $nowTime = time();
        $originalTransactionId = $data['or_trans_id'];
        $transactionId = $data['trans_id'];
        $productId = $data['product_id'];
        $notificationType = $data['notifi_type'];
        $sub_type = $data['sub_type'];
        $notificationUuid = $data['notification_uuid'];
        $purchaseDateMs = $data['purchase_date_ms'];
        $uuid = $data['uuid'];
        $orderId = $uuid ? Util::decryptUuid($uuid) : '';
        $gid = str_replace('apple_pay_', '', $productId);

        //防止重复通知
//        $record = $this->where(['transaction_id' => $transactionId, 'purchase_date_ms' => $purchaseDateMs])->count('id');
        $record = $this->where(['notification_uuid' => $notificationUuid])->count('id');
        if ($record)
        {
            Log::write('苹果支付回调重复通知' . json_encode($data), 'apple_pay', true);
            return true;
        }

        $transactionIdTmp = Util::commentCheck($transactionId, ['notify_type' => $notificationType], 3600);
        if ($transactionIdTmp)
        {
            return true;
        }

        $orderModel = new Orders();
        if ($orderId)
        {
            $tmp = $orderModel->where('order_id', $orderId)->find();
            if (!$tmp)
            {
                $tmp = (new ZhunleUserAccountRecord())->where('order_id', $orderId)->find();
            }
        } else
        {
            $tmp = $orderModel->where(['order_type' => 8, 'transaction_id' => $transactionId])->find();
            if (!$tmp)
            {
                $tmp = (new ZhunleUserAccountRecord())->where('transaction_id', $transactionId)->find();
            }
        }
        if (!$tmp)
        {
            Log::write('苹果支付回调订单不存在' . json_encode($data), 'apple_pay', true);
            return true;
        }
        $tmp['order_type'] = (int)$tmp['order_type'];
        if ($tmp['order_type'] !== 8 && $tmp['status'])
        {
            Log::write('苹果支付回调订单已处理' . json_encode($data), 'apple_pay', true);
            return true;
        }


        $isNeedCreateOrder = false;//是否需要生成订单
        $isNeedUpdateOrder = false;//是否需要更新订单
        $isNeedUpdateVipEndTime = false;//是否需要更新Vip信息
        $subStatus = false;//订阅状态

        //连续订阅
        //订阅状态有两种情况  1=>在APP内购买后回调  2=>订阅过期后在苹果端开启订阅
        if ($notificationType === 'SUBSCRIBED' && in_array($gid, [20106, 20105, 20112, 20111], false) && in_array($tmp['status'], [1, 4], false))
        {
            //判断当前票据是否已被使用
            $transactionOrder = $orderModel->where('transaction_id', $transactionId)->count('id');
            if ($transactionOrder)
            {
                Log::write('苹果支付回调票据已使用' . json_encode($data), 'apple_pay', true);
                return true;
            }
        }

        //查询原始交易绑定的用户ID,订阅状态
        switch ($notificationType)
        {
            case 'DID_CHANGE_RENEWAL_PREF'://用户对其订阅计划进行了更改
                if ($sub_type === 'UPGRADE')//用户升级了其订阅。升级将立即生效，开始新的计费周期，用户将收到上一周期未使用部分的按比例退款
                {
                    //todo 剩余原订阅天数 / 订阅周期  * 原订阅金额 = 可退金额  (10美元/月 * (1月 - 20天) / 30 = 10 * 0.33 = 3.3美元)
                    $isNeedCreateOrder = true;
                    $isNeedUpdateVipEndTime = true;
                }
//                elseif ($sub_type === 'DOWNGRADE')//用户会降级或交叉分级其订阅。降级将在下次续订时生效，不会影响当前有效的计划。
//                {
//
//                }
                break;
            case 'DID_CHANGE_RENEWAL_STATUS'://DID_CHANGE_RENEWAL_STATUS - 订阅续订状态进行了更改
                if ($sub_type === 'AUTO_RENEW_ENABLED')//用户重新启用订阅自动续订
                {
                    $subStatus = 1;
                } elseif ($sub_type === 'AUTO_RENEW_DISABLED')//用户关闭了订阅自动续费，或者用户申请退款后App Store关闭了订阅自动续费
                {
                    $subStatus = 2;
                }
                break;
            case 'DID_FAIL_TO_RENEW'://订阅由于计费问题而续订失败。订阅进入计费重试周期
                if ($sub_type === 'GRACE_PERIOD')//在宽限期内继续提供服务
                {

                } else//订阅不在宽限期内，你可以停止提供订阅服务。
                {
                    $subStatus = 2;
                }
                break;
            case 'DID_RENEW'://DID_RENEW -订阅已成功续订
                //之前续订失败的过期订阅已成功续订 sub_type = BILLING_RECOVERY
                $isNeedCreateOrder = true;
                $isNeedUpdateVipEndTime = true;
                break;
            case 'EXPIRED'://EXPIRED - 订阅已过期
                $subStatus = 2;
                break;
            case 'GRACE_PERIOD_EXPIRED'://计费宽限期已结束，无需续订订阅，因此您可以关闭对服务或内容的访问权限
                $subStatus = 2;
                break;
//            case 'OFFER_REDEEMED'://用户兑换了促销优惠或优惠代码。
//                if ($sub_type === 'INITIAL_BUY')//用户将优惠兑换为首次购买
//                {
//
//                } elseif ($sub_type === 'RESUBSCRIBE')//用户兑换了重新订阅非活动订阅的优惠
//                {
//
//                } elseif ($sub_type === 'UPGRADE')//用户兑换了升级其有效订阅的提议，该优惠将立即生效。
//                {
//
//                } elseif ($sub_type === 'DOWNGRADE')//用户兑换了降级其有效订阅的优惠，该优惠将在下一个续订日期生效
//                {
//
//                }
//                break;
            case 'REFUND'://REFUND - 退款处理交易
                $this->startTrans();
                try
                {
                    if ($tmp['order_type'] === 9)
                    {
                        //  准币扣除
                        (new ZhunleUserAccount())->refund($tmp['uid'], $tmp, $tmp['total_amount'], 6, $transactionId);
                    } else
                    {
                        (new Orders())->UpdateData($tmp['order_id'], ['status' => 3, 'return_time' => $nowTime], 3);
                        //添加退款数据
                        $refundData = [
                            'uid' => $tmp['uid'],
                            'order_id' => $tmp['order_id'],
                            'refund_price' => $tmp['total_amount'],
                            'order_type' => $tmp['order_type'],
                            'out_refund_no' => $transactionId,
                            'trade_type' => 9,
                            'create_time' => $nowTime
                        ];
                        (new AppOrdersRefund())->saveData($refundData);
                        $cache = CacheManage::getInstance();
                        switch ($tmp['order_type'])
                        {
                            case 3:
                            case 4:
                                $fortuneModel = new Fortune();
                                $history = $fortuneModel->where(['id' => $tmp['fid']])->column('rids', 'id');
                                $frids = array_values($history);
                                $id = explode(',', current($frids));
                                if ($tmp['order_type'] === 3)
                                {
                                    (new MonthFortune())->where(['order_id' => $tmp['order_id']])->delete();
                                    foreach ($id as $item)
                                    {
                                        $cache->setCacheConfig('fortune.fortune_month')
                                            ->setCacheKeyDetail('list_v2', $item . ':0')->rmCache('list_v2');
                                    }
                                } elseif ($tmp['order_type'] === 4)
                                {
                                    (new YearFortune())->where(['order_id' => $tmp['order_id']])->delete();
                                    foreach ($id as $item)
                                    {
                                        $cache->setCacheConfig('fortune.fortune_year')
                                            ->setCacheKeyDetail('list_v2', $item)->rmCache('list_v2');
                                    }
                                }
                                break;
                            case 7:
                                $orderGoodsModel = new OrdersGoods();
                                $natalReportModel = new NatalReport();
                                $history = $orderGoodsModel->where(['oid' => $tmp['id']])->column('rid', 'oid');
                                $id = array_values($history);
                                //删除报告的结果数据，因查看详情时使用了结果表的数据
                                $natalReportModel->where(['order_num' => $tmp['order_id']])->delete();
                                //删除报告缓存
                                $cache->setCacheConfig('natal.report', $tmp['uid'] . ':' . $id[0])->rmCache();
                                $natalReportModel->where(['order_num' => $tmp['order_id']])->delete();
                                foreach ($id as $item)
                                {
                                    $key = $tmp['uid'] . ':' . $item;
                                    $cache->setCacheConfig('natal.report', $key)->setCacheKeyDetail('details_v2', $key)->rmCache('details_v2');
                                }
                                break;
                            case 8:
                                $this->userVipExpire($tmp['uid'], $orderId);
                                break;
                        }
                    }
                    //苹果退款记录
                    $this->saveData([
                        'notification_uuid' => $notificationUuid,
                        'notification_type' => $notificationType,
                        'uid' => $tmp['uid'],
                        'total_amount' => $tmp['total_amount'],
                        'original_transaction_id' => $originalTransactionId,
                        'transaction_id' => $transactionId,
                        'order_id' => $tmp['order_id'],
                        'product_id' => $productId,
                        'purchase_date_ms' => $purchaseDateMs,
                        'create_time' => $nowTime,
                        'extend' => json_encode(['sub_type' => $sub_type], true)
                    ]);
                    $this->commit();
                }
                catch (\Exception $e)
                {
                    $this->rollback();
                    Log::write('UserAppleNotifyRecord model => ()异常：' . $e->getMessage() . '失败信息：' . $e->getFile() . ':' . $e->getLine() . '请求数据:' . json_encode($data, JSON_UNESCAPED_UNICODE), 'error', true);
                    return false;
                }
                //退款钉钉通知
                $t = microtime();
                $time = substr($t, 11, 10) . substr($t, 2, 3);
                $sec = 'SEC4c9a939cb683066a8816fd2c18cd546bc30fed06e02b079f3fe1463bc817a483';
                $sign = urldecode(base64_encode(hash_hmac('sha256', $time . "\n" . $sec, $sec, true)));
                $url = "https://oapi.dingtalk.com/robot/send?access_token=b5ba626f07afcc625c59a8ca2624388fd084936d92a0c39703cf62bdc1fd1666&timestamp={$time}&sign={$sign}";
                $host = Env::get('host.name');
                $msg = '## ' . $host . "苹果退款成功通知";
                $msg .= "\r\n > 用户：" . $tmp['uid'] . PHP_EOL;
                $msg .= "\r\n > 订单编号：" . $tmp['order_id'] . PHP_EOL;
                $msg .= "\r\n > 时间：" . date('Y-m-d H:i:s') . PHP_EOL;
                Util::sendDingMsg($url, '苹果退款成功', $msg);
                return true;
//                    case 'RENEWAL_EXTENDED'://RENEWAL_EXTENDED - App Store 延长了特定订阅的订阅续订日期
//                        $subStatus = 1;
//                        $expiration_time = abs($goods['expiration_time']);
//                        break;
            case 'SUBSCRIBED'://SUBSCRIBED - 用户订阅了产品
                //APP订阅时间增加
//                if ($sub_type === 'INITIAL_BUY')//用户首次通过“家人共享”购买或获得了订阅的访问权限
//                {
//
//                } elseif ($sub_type === 'RESUBSCRIBE')//用户通过“家人共享”重新订阅或接收了对同一订阅或同一订阅组中其他订阅的访问权限。
//                {
//
//                }
                $isNeedUpdateOrder = true;
                $isNeedUpdateVipEndTime = true;
                break;
            case 'TEST'://测试服务器是否正在接收通知。
                break;
        }

        $totalAmount = $tmp['total_amount'];

        //准币处理
        if ($tmp['order_type'] === 9)
        {
            //更新用户准币明细状态
            OrdersLib::UpdateCoin($tmp['order_id'], 9, $totalAmount, $tmp['uid'], 1, 9, $transactionId);
            //苹果回调记录
            $this->saveData([
                'notification_uuid' => $notificationUuid,
                'notification_type' => $notificationType,
                'uid' => $tmp['uid'],
                'total_amount' => $totalAmount,
                'original_transaction_id' => $originalTransactionId,
                'transaction_id' => $transactionId,
                'order_id' => $tmp['order_id'],
                'product_id' => $productId,
                'purchase_date_ms' => $purchaseDateMs,
                'create_time' => $nowTime,
                'extend' => json_encode(['sub_type' => $sub_type], true)
            ]);
            return true;
        }

        if ($tmp['order_type'] === 8)
        {
            $orderId = $tmp['order_id'];
            //VIP处理
            //生成订单
            if ($isNeedCreateOrder)
            {
                $order_type_des = OrdersLib::createOrderId(8);
                $goods = config('apple_pay_goods.ios_vip_goods');
                $totalAmount = $goods[$gid]['now_prize'];
                $orderId = $order_type_des['order_id'];
                $UserVip = OrdersLib::getUserVipTime($tmp['uid'], $gid);//返回时间为时间戳
                $extend = [
                    'vip_start_time' => $UserVip['vip_start_time'],
                    'vip_end_time' => $UserVip['vip_end_time']

                ];
                $orderModel->SaveData(
                    [
                        'order_type' => 8,
                        'uid' => $tmp['uid'],
                        'gid' => $gid,
                        'order_id' => $orderId,
                        'transaction_id' => $transactionId,
                        'reid' => 0,
                        'fid' => 0,
                        'trade_type' => 9,
                        'total_amount' => $totalAmount,
                        'create_time' => $nowTime,
                        'pay_time' => $nowTime,
                        'status' => 4,
                        'account' => 0,
                        'extend' => json_encode($extend, true)
                    ]);
                $tmp['order_id'] = $orderId;
            } //更新订单状态
            else if ($isNeedUpdateOrder)
            {
                $orderModel->UpdateData($orderId, ['status' => 4, 'transaction_id' => $transactionId, 'pay_time' => $nowTime], 4);
            }
            //vip更新状态和星力值
            if ($isNeedUpdateVipEndTime)
            {
                $this->updateLuckyTask($tmp);
                OrdersLib::UpdateVipStatus($tmp, $gid);
            } //更新订阅状态
            elseif ($subStatus)
            {
                (new ZlUserVip())->UpdateData($tmp['uid'], ['apple_status' => $subStatus, 'update_time' => $nowTime]);
            }
            //苹果回调记录
            $this->saveData([
                'notification_uuid' => $notificationUuid,
                'notification_type' => $notificationType,
                'uid' => $tmp['uid'],
                'total_amount' => $totalAmount,
                'original_transaction_id' => $originalTransactionId,
                'transaction_id' => $transactionId,
                'order_id' => $orderId,
                'product_id' => $productId,
                'purchase_date_ms' => $purchaseDateMs,
                'create_time' => $nowTime,
                'extend' => json_encode(['sub_type' => $sub_type], true)
            ]);
            return true;
        }

        if (in_array($tmp['order_type'], [3, 4, 7], true))
        {
            (new \app\common\service\Orders())->notify_handle($tmp['order_id'], $tmp['total_amount'], 9, $transactionId);
            return true;
        }
        return true;
    }

    /**
     * 幸运星的其他任务完成
     * @param $tmp
     * @return void
     */
    private function updateLuckyTask($tmp)
    {
        try
        {
            $extendTmp = json_decode($tmp['extend'], true);
            //2.8.5以后幸运星完成其他任务
            $orderVersion = isset($extendTmp['app_info']) ? $extendTmp['app_info']['version'] : '';
            if ($orderVersion)
            {
                if (Util::CheckAppVersion('2.8.5', $orderVersion) !== '小')
                {
                    //其他任务完成
                    $taskInfo = config('lucky_task.order_task');
                    if (isset($taskInfo[$tmp['order_type']]))
                    {
                        (new AppLuckyTaskRecord())->setOtherTaskSuccess($tmp['uid'], $taskInfo[$tmp['order_type']], $tmp['order_id']);
                    }
                }
            }
        }
        catch (\Exception $e)
        {
            \think\Log::write('苹果回调幸运星任务完成异常：' . $e->getMessage() . '失败信息：' . $e->getFile() . ':' . $e->getLine(), 'error', true);
        }
    }

    /**
     * 记录退款记录
     * @param $data
     * @return void
     */
    public function saveData($data)
    {
        try
        {
            $this->insertGetId($data);
        }
        catch (\Exception $e)
        {
            Log::write('UserAppleSubsAccountRecord model => ()异常：' . $e->getMessage() . '失败信息：' . $e->getFile() . ':' . $e->getLine(), 'error');
        }
    }


    /**
     * 退款关闭VIP,VIP等级和星力值降级,关闭所有免费券
     * @param $uid
     * @param $orderId
     * @return void
     * @throws PDOException
     */
    public function userVipExpire($uid, $orderId)
    {
        $userVipModel = new ZlUserVip();
        $userVip = $userVipModel->getInfoById($uid);
        if ($userVip['vip_level'] > 1)
        {
            $vipLevel = $userVip['vip_level'] - 1;
        } else
        {
            $vipLevel = 1;
        }
        $time = time();
        $vipLevelInfo = (new ZlVip())->getLevelAll();
        $orderInfo = (new Orders())->getInfoById($orderId, ['uid', 'extend']);
        $extend = isset($orderInfo['extend']) ? json_decode($orderInfo['extend'], true) : [];
        //会员过期
        $userVipData = [
            'is_valid' => 0,
            'star_num' => $vipLevelInfo[$vipLevel - 1]['star_num'],
            'vip_level' => $vipLevel,
            'end_time' => $time,
            'update_time' => $time
        ];
        if (isset($extend['vip_end_time']))
        {
            if ($extend['vip_end_time'] < $userVip['end_time'])
            {
                unset($userVipData['is_valid'], $userVipData['end_time']);
            } else
            {
                //  赠送的免费券都失效
                $userCouponModel = new UserCoupon();
                $couponInfo = $userCouponModel
                    ->alias('uc')
                    ->join('wechat_backup_07_18_14_43_00.zl_coupon_attr c', 'uc.c_id=c.id')
                    ->where(['uc.uid' => $uid, 'c.type' => 5])
                    ->column('uc.is_give', 'uc.id');
                $userCids = array_keys($couponInfo);
                // 优惠券锁定 并自动更新 优惠券详情缓存
                $userCouponModel->where(['id' => ['in', $userCids]])->update([
                    'status' => 1,
                    'update_time' => $time
                ]);
                foreach ($couponInfo as $cid => $giveStatus)
                {
                    $isGive = (int)$giveStatus;
                    //删除未使用内的缓存KEY
                    $userCouponModel->listDataDel($uid, [$cid], 1);
                    // 删除可赠与内的缓存KEY
                    if ($isGive === 1)
                    {
                        $userCouponModel->listDataDel($uid, [$cid], 2);
                    }
                    // 新增已失效过期内的缓存
                    $userCouponModel->listDataAdd($uid, [$cid => $time], 3);
                }
            }
        }
        $userVipModel->where('uid', $uid)->update($userVipData);
        // 更新缓存
        CacheManage::getInstance()->setCacheConfig($userVipModel->cacheModel, $uid)->setCache($userVipData);
        //VIP等级和星力值降级
        (new ZlUserVip())->updateStarNum($uid, 15);
    }
}
